export default class EventBus {
    constructor(options){
      this.init(options)
    }
    init = function (options) {
      let vm = this;
      vm._events = {}
      // init data
      for (const key in options.data()) {
          vm[key] = options.data()[key]
      }
      //init methods
      for(let key in options.methods){
          vm[key] = options.methods[key] == null ? noop : options.methods[key].bind(vm)
      }
    }
    $emit(event) {
      const vm = this
      // 拿出触发事件对应的回调函数列表
      let cbs = vm._events[event]
      if (cbs) {
        // $emit方法可以传参，这些参数会在调用回调函数的时候传进去
        const args = [...arguments]
        args.shift()
        // 遍历回调函数列表，调用每个回调函数
        for (let i = 0, l = cbs.length; i < l; i++) {
          cbs[i].apply(vm, args)
        }
      }
      return vm
    }
    $on(event, fn) {
      const vm = this
      // 我们传入的要监听的事件可能为数组，这时候对数组里的每个事件再递归调用$on方法
      if (Array.isArray(event)) {
        for (let i = 0, l = event.length; i < l; i++) {
          vm.$on(event[i], fn)
        }
      } else {
        // 之前已经有监听event事件，则将此次监听的回调函数添加到其数组中，否则创建一个新数组并添加fn
        (vm._events[event] || (vm._events[event] = [])).push(fn)
      }
      return vm
    }
    $off(event, fn) {
      const vm = this
      // all
      if (!arguments.length) {
      // 如果没有传参数，则清空所有事件的监听函数
        vm._events = Object.create(null)
        return vm
      }
      // 如果传的event是数组，则对该数组里的每个事件再递归调用$off方法
      if (Array.isArray(event)) {
        for (let i = 0, l = event.length; i < l; i++) {
          vm.$off(event[i], fn)
        }
        return vm
      }
      // 获取当前event里所有的回调函数
      const cbs = vm._events[event]
      // 如果不存在回调函数，则直接返回，因为没有可以移除监听的内容
      if (!cbs) {
        return vm
      }
      // 如果没有指定要移除的回调函数，则移除该事件下所有的回调函数
      if (!fn) {
        vm._events[event] = null
        return vm
      }
      // 指定了要移除的回调函数
      let cb
      let i = cbs.length
      while (i--) {
        cb = cbs[i]
        // 在事件对应的回调函数数组里面找出要移除的回调函数，并从数组里移除
        if (cb === fn || cb.fn === fn) {
          cbs.splice(i, 1)
          break
        }
      }
      return vm
    }
}
